#pragma once
#include <boost/array.hpp>

#include "Business/Variety.h"

class Price
{
public:
	Price(double price = 0.00,UINT quantity = 0)
		:m_price(price),m_quantity(quantity)
	{
	}

	double GetPrice() const {return m_price;}
	int GetQuantity() const {return m_quantity;}

	bool operator==(Price const& other) const
	{
		return m_price == other.GetPrice() && m_quantity == other.GetQuantity();
	}

	bool operator!=(Price const& other) const
	{
		return !operator==(other);
	}
private:
	double m_price;
	int m_quantity;
};


typedef boost::array<Price,5> Prices;

class Market
{
public:
	Market()
		:m_contract(-1),m_variety(Variety("UNDIFINED",-1,-1)),
		m_lastPrice(0),	m_openInterest(0),
		m_buyPrices(Prices()),m_sellPrices(Prices()),
		m_upperLimit(0),m_lowerLimit(0),m_preSettlementPrice(0),m_time(CTime::GetCurrentTime())
	{
	}

	Market(int contract,Variety const& code,
		double lastPrice,double openInterest,
		Prices const& buyPrices,Prices const& sellPrices,
		double upperLimit,double lowerLimmit,
		double preSettlementPrice, CTime const& time = CTime::GetCurrentTime())
		:m_contract(contract), m_variety(code), 
			m_lastPrice(lastPrice),m_openInterest(openInterest),
		 m_buyPrices(buyPrices), m_sellPrices(sellPrices),
		 m_upperLimit(upperLimit), m_lowerLimit(lowerLimmit),
		 m_preSettlementPrice(preSettlementPrice),m_time(time)
	{
	}
	
	Market(Market const& market)
		:m_contract(market.GetContract()),
		m_variety(market.GetVariety()),
		m_lastPrice(market.GetLastPrice()),
		m_openInterest(market.GetOpenInterest()),
		m_buyPrices(market.GetBuyPrices()),
		m_sellPrices(market.GetSellPrices()),
		m_upperLimit(market.GetUpperLimit()),
		m_lowerLimit(market.GetLowerLimit()),
		m_preSettlementPrice(market.GetPreSettlementPrice()),
		m_time(market.GetTime())
	{
	}

	int GetSpecialUpperLimit() const { return m_specialUpperLimit; }
	void SetSpecialUpperLimit(int specialUpperLimit) { m_specialUpperLimit = specialUpperLimit; }
	int GetSpecialLowerLimit() const { return m_specialLowerLimit; }
	void SetSpecialLowerLimit(int specialLowerLimit) { m_specialLowerLimit = specialLowerLimit; }

	int const& GetContract() const {return m_contract;}
	char const* GetCode() const {return m_variety.GetCode();}
	Variety const& GetVariety() const {return m_variety;}
	int GetMultiple() const {return GetVariety().GetMultiple();}
	double GetMarginRate() const {return GetVariety().GetTotalMargin();}
	double GetLastPrice() const {return m_lastPrice;}
	Prices const& GetBuyPrices() const {return m_buyPrices;}
	Prices const& GetSellPrices() const {return m_sellPrices;}
	double GetUpperLimit() const {return m_upperLimit;}
	double GetLowerLimit() const {return m_lowerLimit;}


	double GetPreSettlementPrice() const {return m_preSettlementPrice;}
	double GetOpenInterest() const { return m_openInterest; };
	CTime const& GetTime() const { return m_time; }
	int GetMinPriceUnit() const { return m_variety.GetUnit();}

	Price const& GetBuy1() const {return m_buyPrices[0];}
	Price const& GetSell1() const {return m_sellPrices[0];}

	bool IsValid() const{return m_contract > 0;}

	void UpdatePrice(Market const& market)
	{
		m_lastPrice = market.GetLastPrice();
		m_buyPrices = market.GetBuyPrices();
		m_sellPrices = market.GetSellPrices();
		m_upperLimit = market.GetUpperLimit();
		m_lowerLimit = market.GetLowerLimit();
		m_preSettlementPrice = market.GetPreSettlementPrice();
		m_openInterest = market.GetOpenInterest();
	}

	double CalculateMargin(int quantity,Operation::TYPE operation) const
	{
		if (operation == Operation::OPEN)
		{
			return GetPreSettlementPrice() * quantity * GetMarginRate() * GetVariety().GetMultiple();
		}
		return 0.00;
	}
	
	double CalculateMargin(double price, int quantity,Operation::TYPE operation) const
	{
		if (operation == Operation::OPEN)
		{
			return price * quantity * GetMarginRate() * GetVariety().GetMultiple();
		}
		return 0.00;
	}
	
	double CalculateCharge(double price, int quantity, Operation::TYPE operation) const
	{
		return GetVariety().CalculateCharge(price, quantity, operation);
	}
	
	double CalculateFreezeAmount(double price, int quantity, Operation::TYPE operation) const
	{
		return CalculateMargin(quantity,operation) + CalculateCharge(price,quantity,operation);
	}

	bool IsCloseLimit() const
	{
		const double CLOSE_TO_PERCENT = 0.1 * 0.05;
		bool isCloseToUpperLimit = GetLastPrice() >= GetUpperLimit() - GetUpperLimit()*CLOSE_TO_PERCENT;
		bool isCloseToLowerLimit = GetLastPrice() <= GetLowerLimit() + GetLowerLimit()*CLOSE_TO_PERCENT;
		return isCloseToUpperLimit || isCloseToLowerLimit;
	}
private:

	int m_contract;
	Variety m_variety;
	double m_lastPrice;
	Prices m_buyPrices;
	Prices m_sellPrices;
	double m_upperLimit;
	double m_lowerLimit;
	double m_preSettlementPrice;
	double m_openInterest;
	CTime m_time;

	int m_specialUpperLimit;
	int m_specialLowerLimit;
};

